GDK: Use GdkCursor objects to keep track of W32 cursors, not HCURSOR
authorРуслан Ижбулатов <lrn1986@gmail.com>
Sun, 3 May 2015 21:29:35 +0000 (21:29 +0000)
committerРуслан Ижбулатов <lrn1986@gmail.com>
Wed, 20 May 2015 08:40:43 +0000 (08:40 +0000)
In particular this means that cursors are disposed of by the way of
g_object_unref(), not DestroyCursor (which is documented to not to be
used on certain kinds of cursors, and we can't tell which is which).

It should also alleviate any concerns about destroying cursors that
are still in use by other windows, except for cases where we would
somehow get our hands on a HCURSOR that someone else is using and we
make a GdkCursor out of it and later unref and finalize it while it
is still in use.

It also removes the need to call CopyCursor(), which makes animated
cursors into non-animated ones as a side-effect (supposed to be a bug,
but try explaining that to MS). Now cursors should be animated (if
the are set up as such in the OS).

https://bugzilla.gnome.org/show_bug.cgi?id=697477

gdk/win32/gdkdevice-virtual.c
gdk/win32/gdkevents-win32.c
gdk/win32/gdkprivate-win32.h
gdk/win32/gdkwindow-win32.c
gdk/win32/gdkwindow-win32.h

index 4371c164036168aa4c7edaedcbbae5508b91b8f5..2ed341f106fee815fe36248a995c072f80610147 100644 (file)
@@ -157,30 +157,23 @@ gdk_device_virtual_set_window_cursor (GdkDevice *device,
                                      GdkWindow *window,
                                      GdkCursor *cursor)
 {
-  GdkWin32Cursor *cursor_private;
   GdkWindow *parent_window;
   GdkWindowImplWin32 *impl;
-  HCURSOR hcursor;
-  HCURSOR hprevcursor;
+  GdkCursor *replacement_cursor;
+  GdkCursor *previous_cursor;
 
   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
-  cursor_private = (GdkWin32Cursor*) cursor;
 
-  hprevcursor = impl->hcursor;
+  previous_cursor = impl->cursor;
 
-  if (!cursor)
-    hcursor = NULL;
-  else
-    hcursor = cursor_private->hcursor;
-
-  if (hcursor != NULL)
+  if (cursor != NULL && GDK_WIN32_CURSOR (cursor)->hcursor != NULL)
     {
       /* If the pointer is over our window, set new cursor */
       GdkWindow *curr_window = gdk_window_get_device_position (window, device, NULL, NULL, NULL);
 
       if (curr_window == window ||
           (curr_window && window == gdk_window_get_toplevel (curr_window)))
-        SetCursor (hcursor);
+        SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor);
       else
         {
           /* Climb up the tree and find whether our window is the
@@ -188,12 +181,12 @@ gdk_device_virtual_set_window_cursor (GdkDevice *device,
            * new cursor.
            */
           while (curr_window && curr_window->impl &&
-                 !GDK_WINDOW_IMPL_WIN32 (curr_window->impl)->hcursor)
+                 !GDK_WINDOW_IMPL_WIN32 (curr_window->impl)->cursor)
             {
               curr_window = curr_window->parent;
               if (curr_window == GDK_WINDOW (window))
                 {
-                  SetCursor (hcursor);
+                  SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor);
                   break;
                 }
             }
@@ -204,26 +197,26 @@ gdk_device_virtual_set_window_cursor (GdkDevice *device,
    * use before we destroy it, in case we're not over our window but
    * the cursor is still set to our old one.
    */
-  if (hprevcursor != NULL &&
-      GetCursor () == hprevcursor)
+  if (previous_cursor != NULL &&
+      GetCursor () == GDK_WIN32_CURSOR (previous_cursor)->hcursor)
     {
       /* Look for a suitable cursor to use instead */
-      hcursor = NULL;
+      replacement_cursor = NULL;
       parent_window = GDK_WINDOW (window)->parent;
 
-      while (hcursor == NULL)
+      while (replacement_cursor == NULL)
         {
           if (parent_window)
             {
               impl = GDK_WINDOW_IMPL_WIN32 (parent_window->impl);
-              hcursor = impl->hcursor;
+              replacement_cursor = impl->cursor;
               parent_window = parent_window->parent;
             }
           else
-            hcursor = LoadCursor (NULL, IDC_ARROW);
+            replacement_cursor = _gdk_win32_display_get_cursor_for_type (_gdk_display, GDK_LEFT_PTR);
         }
 
-      SetCursor (hcursor);
+      SetCursor (GDK_WIN32_CURSOR (replacement_cursor)->hcursor);
     }
 }
 
@@ -266,31 +259,22 @@ gdk_device_virtual_grab (GdkDevice    *device,
                         guint32       time_)
 {
   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
-  HCURSOR hcursor;
-  GdkWin32Cursor *cursor_private;
-
-  cursor_private = (GdkWin32Cursor*) cursor;
 
   if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
     {
-      if (!cursor)
-       hcursor = NULL;
-      else if ((hcursor = CopyCursor (cursor_private->hcursor)) == NULL)
-       WIN32_API_FAILED ("CopyCursor");
-
       if (_gdk_win32_grab_cursor != NULL)
        {
-         if (GetCursor () == _gdk_win32_grab_cursor)
+         if (GetCursor () == GDK_WIN32_CURSOR (_gdk_win32_grab_cursor)->hcursor)
            SetCursor (NULL);
-         DestroyCursor (_gdk_win32_grab_cursor);
+         g_clear_object (&_gdk_win32_grab_cursor);
        }
 
-      _gdk_win32_grab_cursor = hcursor;
+      _gdk_win32_grab_cursor = cursor;
 
       if (_gdk_win32_grab_cursor != NULL)
-       SetCursor (_gdk_win32_grab_cursor);
-      else if (impl->hcursor != NULL)
-       SetCursor (impl->hcursor);
+       SetCursor (GDK_WIN32_CURSOR (_gdk_win32_grab_cursor)->hcursor);
+      else if (impl->cursor != NULL)
+       SetCursor (GDK_WIN32_CURSOR (impl->cursor)->hcursor);
       else
        SetCursor (LoadCursor (NULL, IDC_ARROW));
 
@@ -317,9 +301,9 @@ gdk_device_virtual_ungrab (GdkDevice *device,
     {
       if (_gdk_win32_grab_cursor != NULL)
        {
-         if (GetCursor () == _gdk_win32_grab_cursor)
+         if (GetCursor () == GDK_WIN32_CURSOR (_gdk_win32_grab_cursor)->hcursor)
            SetCursor (NULL);
-         DestroyCursor (_gdk_win32_grab_cursor);
+         g_clear_object (&_gdk_win32_grab_cursor);
        }
       _gdk_win32_grab_cursor = NULL;
 
index dc18405520ea00284a29bf635df2fc85630b67f2..eed1bc6e5d91fab02d02ac295164800b57973474 100644 (file)
@@ -106,7 +106,7 @@ static gboolean gdk_event_dispatch (GSource     *source,
 static GList *client_filters;  /* Filters for client messages */
 extern gint       _gdk_input_ignore_core;
 
-HCURSOR _gdk_win32_grab_cursor;
+GdkCursor *_gdk_win32_grab_cursor;
 
 static GSourceFuncs event_funcs = {
   gdk_event_prepare,
@@ -1840,7 +1840,7 @@ gdk_event_translate (MSG  *msg,
   MINMAXINFO *mmi;
   LONG style;
   HWND hwnd;
-  HCURSOR hcursor;
+  GdkCursor *cursor;
   BYTE key_state[256];
   HIMC himc;
   WINDOWPOS *windowpos;
@@ -2633,19 +2633,19 @@ gdk_event_translate (MSG  *msg,
        break;
 
       if (grab_window != NULL && _gdk_win32_grab_cursor != NULL)
-       hcursor = _gdk_win32_grab_cursor;
-      else if (!GDK_WINDOW_DESTROYED (window))
-       hcursor = GDK_WINDOW_IMPL_WIN32 (window->impl)->hcursor;
+       cursor = _gdk_win32_grab_cursor;
+      else if (!GDK_WINDOW_DESTROYED (window) && GDK_WINDOW_IMPL_WIN32 (window->impl)->cursor != NULL)
+       cursor = GDK_WINDOW_IMPL_WIN32 (window->impl)->cursor;
       else
-       hcursor = NULL;
+       cursor = NULL;
 
-      if (hcursor != NULL)
-       {
-         GDK_NOTE (EVENTS, g_print (" (SetCursor(%p)", hcursor));
-         SetCursor (hcursor);
-         return_val = TRUE;
-         *ret_valp = TRUE;
-       }
+      if (cursor != NULL)
+        {
+         GDK_NOTE (EVENTS, g_print (" (SetCursor(%p)", cursor));
+         SetCursor (GDK_WIN32_CURSOR (cursor)->hcursor);
+          return_val = TRUE;
+          *ret_valp = TRUE;
+        }
       break;
 
     case WM_SYSCOMMAND:
index 93166a912f1515c9375145dd346a80fd10b87f87..98b64a3edbf4e68973a8d259e3057598a0c0ad87 100644 (file)
@@ -361,7 +361,7 @@ extern GHashTable   *_format_atom_table;
 /* Hold the result of a delayed rendering */
 extern HGLOBAL         _delayed_rendering_data;
 
-extern HCURSOR _gdk_win32_grab_cursor;
+extern GdkCursor *_gdk_win32_grab_cursor;
 
 HGLOBAL _gdk_win32_selection_convert_to_dib (HGLOBAL  hdata,
                                             GdkAtom  target);
index 43fb2d02ad7256e8c1169d6edd0a716dfb9aab61..765ae0107187f7162b265ed1c7be20635f1751a6 100644 (file)
@@ -132,7 +132,7 @@ static void
 gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
 {
   impl->toplevel_window_type = -1;
-  impl->hcursor = NULL;
+  impl->cursor = NULL;
   impl->hicon_big = NULL;
   impl->hicon_small = NULL;
   impl->hint_flags = 0;
@@ -160,14 +160,7 @@ gdk_window_impl_win32_finalize (GObject *object)
       gdk_win32_handle_table_remove (window_impl->handle);
     }
 
-  if (window_impl->hcursor != NULL)
-    {
-      if (GetCursor () == window_impl->hcursor)
-       SetCursor (NULL);
-
-      GDI_CALL (DestroyCursor, (window_impl->hcursor));
-      window_impl->hcursor = NULL;
-    }
+  g_clear_object (&window_impl->cursor);
 
   if (window_impl->hicon_big != NULL)
     {
@@ -1957,55 +1950,33 @@ gdk_win32_window_set_device_cursor (GdkWindow *window,
                                     GdkCursor *cursor)
 {
   GdkWindowImplWin32 *impl;
-  GdkWin32Cursor *cursor_private;
-  HCURSOR hcursor;
-  HCURSOR hprevcursor;
+  GdkCursor *previous_cursor;
 
   impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
-  cursor_private = (GdkWin32Cursor*) cursor;
 
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
-  if (!cursor)
-    hcursor = NULL;
-  else
-    hcursor = cursor_private->hcursor;
-
   GDK_NOTE (MISC, g_print ("gdk_win32_window_set_cursor: %p: %p\n",
                           GDK_WINDOW_HWND (window),
-                          hcursor));
+                          cursor));
 
   /* First get the old cursor, if any (we wait to free the old one
    * since it may be the current cursor set in the Win32 API right
    * now).
    */
-  hprevcursor = impl->hcursor;
+  previous_cursor = impl->cursor;
 
   GDK_DEVICE_GET_CLASS (device)->set_window_cursor (device, window, cursor);
 
-  if (hcursor == NULL)
-    impl->hcursor = NULL;
+  if (cursor)
+    impl->cursor = g_object_ref (cursor);
   else
-    {
-      /* We must copy the cursor as it is OK to destroy the GdkCursor
-       * while still in use for some window. See for instance
-       * gimp_change_win_cursor() which calls gdk_window_set_cursor
-       * (win, cursor), and immediately afterwards gdk_cursor_destroy
-       * (cursor).
-       */
-      if ((impl->hcursor = CopyCursor (hcursor)) == NULL)
-       WIN32_API_FAILED ("CopyCursor");
-      GDK_NOTE (MISC, g_print ("... CopyCursor (%p) = %p\n",
-                              hcursor, impl->hcursor));
-    }
+    impl->cursor = NULL;
 
   /* Destroy the previous cursor */
-  if (hprevcursor != NULL)
-    {
-      GDK_NOTE (MISC, g_print ("... DestroyCursor (%p)\n", hprevcursor));
-      API_CALL (DestroyCursor, (hprevcursor));
-    }
+  if (previous_cursor != NULL)
+    g_object_unref (previous_cursor);
 }
 
 static void
index bc1575c71aa569c8df14cc0706f25a8622deec85..8f17ead0339f4127dcba71085c10cfe5284aea8d 100644 (file)
@@ -55,7 +55,7 @@ struct _GdkWindowImplWin32
 
   gint8 toplevel_window_type;
 
-  HCURSOR hcursor;
+  GdkCursor *cursor;
   HICON   hicon_big;
   HICON   hicon_small;